"""
抓取有效任务的历史数据模块
获取有效的任务列表
获取有效的扫货账号列表
循环任务列表中的任务分配对应的扫货账号
每个任务在执行获取历史数据之前定时等待5-15秒的随机数
获取uu7天历史价格数据与uu历史在售数量的历史数据
把数据保存到commodity_history_data表中
"""
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent))

import time
import random
import traceback
import asyncio
from datetime import datetime, date
from typing import List, Dict, Any, Optional
from decimal import Decimal

from com.db.models import CommodityHistoryData
from com.db.task_manager import TaskManager
from com.db.scan_account_manager import ScanAccountManager
from com.db.history_data_manager import HistoryDataManager
from reqapi.get_commodity_trend import GetCommodityTrendApi
from reqapi.get_template_info import GetTemplateInfoApi
from com.utils.logger import get_logger

# 获取日志记录器
logger = get_logger("历史数据抓取")

class TaskHistoryDataFetcher:
    """任务历史数据抓取类"""
    
    def __init__(self, max_workers=5):
        """
        初始化
        
        Args:
            max_workers: 最大并发协程数
        """
        self.task_manager = TaskManager()
        self.account_manager = ScanAccountManager()
        self.history_data_manager = HistoryDataManager()
        self.max_workers = max_workers
        self.success_count = 0
        self.fail_count = 0
        self.lock = asyncio.Lock()  # 用于协程安全的计数
        
    def log(self, message: str):
        """记录日志"""
        logger.info(message)
        print(message)
        
    def get_active_tasks(self) -> List[Dict[str, Any]]:
        """
        获取有效的任务列表
        
        Returns:
            List[Dict[str, Any]]: 有效任务列表
        """
        self.log("正在获取有效任务列表...")
        try:
            # 获取状态为1（启用）且未禁用的任务
            tasks = self.task_manager.search_tasks(status=1, tags=None)
            # 过滤掉已禁用的任务
            tasks = [task for task in tasks if task.get('disabled', 0) == 0]
            self.log(f"获取到 {len(tasks)} 个有效任务")
            return tasks
        except Exception as e:
            self.log(f"获取有效任务列表失败: {str(e)}")
            return []
            
    def get_active_accounts(self, count: int = 0) -> List[Dict]:
        """
        获取有效的扫货账号列表
        
        Args:
            count: 需要获取的账号数量，0表示获取所有
            
        Returns:
            List[Dict]: 有效账号列表
        """
        self.log("正在获取有效扫货账号列表...")
        try:
            # 使用ScanAccountManager获取活跃的扫货账号
            accounts = self.account_manager.get_active_accounts()
            if not accounts:
                self.log("没有可用的扫货账号")
                return []
                
            # 如果指定了数量，则只返回指定数量的账号
            if count > 0 and count < len(accounts):
                accounts = accounts[:count]
                
            self.log(f"获取到 {len(accounts)} 个有效扫货账号")
            return accounts
        except Exception as e:
            self.log(f"获取有效扫货账号列表失败: {str(e)}")
            return []
    
    async def fetch_history_data(self, task: Dict[str, Any], account_info: Dict) -> bool:
        """
        获取单个任务的历史数据
        
        Args:
            task: 任务信息
            account_info: 账号信息
            
        Returns:
            bool: 是否成功
        """
        try:
            # 获取任务信息
            task_id = task.get('id')
            goods_id = task.get('goods_id')
            name = task.get('name')
            
            # 获取账号信息
            account = account_info
            
            # 随机等待10-25秒
            random_wait = random.randint(10, 25)
            self.log(f"任务 [{name}] 随机等待 {random_wait} 秒...")
            await asyncio.sleep(random_wait)
            
            # 创建API客户端
            trend_api = GetCommodityTrendApi(
                device_id=account.get('device_id', ''),
                device_token=account.get('device_id', ''),
                auth_token=account.get('uu_token', ''),
                uk=account.get('uk', '')
            )
            
            # 获取7天历史价格数据 (order_type=1 表示价格数据)
            self.log(f"正在获取商品 [{name}] 的历史价格数据...")
            # 使用run_in_executor在线程池中执行阻塞操作
            loop = asyncio.get_event_loop()
            price_data = await loop.run_in_executor(
                None, 
                lambda: trend_api.execute(goods_id, day=7, order_type=1)
            )
            
            if not price_data:
                self.log(f"获取商品 [{name}] 的历史价格数据失败")
                return False
                
            # 保存历史价格数据
            trade_list = price_data.get('trade_list', [])
            if trade_list:
                self.log(f"获取到 {len(trade_list)} 条历史价格数据")
                # 批量添加历史价格数据 (his_type=1 表示价格数据)
                await loop.run_in_executor(
                    None,
                    lambda: self.history_data_manager.batch_add_history_data(
                        template_id=goods_id,
                        his_type=1,
                        wear_value=None,  
                        trade_data_list=trade_list
                    )
                )
            else:
                self.log(f"商品 [{name}] 没有历史价格数据")
            
            # 随机等待2-5秒
            random_wait = random.randint(2, 5)
            self.log(f"随机等待 {random_wait} 秒后获取在售数量数据...")
            await asyncio.sleep(random_wait)
            
            # 获取7天历史在售数量数据 (order_type=11 表示在售数量数据)
            self.log(f"正在获取商品 [{name}] 的历史在售数量数据...")
            listing_data = await loop.run_in_executor(
                None,
                lambda: trend_api.execute(goods_id, day=7, order_type=11)
            )
            
            if not listing_data:
                self.log(f"获取商品 [{name}] 的历史在售数量数据失败")
                return False
                
            # 保存历史在售数量数据
            listing_trade_list = listing_data.get('trade_list', [])
            if listing_trade_list:
                self.log(f"获取到 {len(listing_trade_list)} 条历史在售数量数据")
                # 批量添加历史在售数量数据 (his_type=2 表示在售数量数据)
                result = await loop.run_in_executor(
                    None,
                    lambda: self.history_data_manager.batch_add_history_data(
                        template_id=goods_id,
                        his_type=2,
                        wear_value=None,  
                        trade_data_list=listing_trade_list
                    )
                )
                
                if result:
                    self.log(f"商品 [{name}] 的历史数据保存成功")
                    return True
                else:
                    self.log(f"保存商品 [{name}] 的历史在售数量数据失败")
                    return False
            else:
                self.log(f"商品 [{name}] 没有历史在售数量数据")
                return False
                
        except Exception as e:
            self.log(f"获取任务 [{task.get('name', '')}] 的历史数据失败: {str(e)}")
            traceback.print_exc()
            return False
            
    async def worker(self, task_queue, account_info):
        """
        工作协程函数
        
        Args:
            task_queue: 任务队列
            account_info: 账号信息
        """
        while not task_queue.empty():
            try:
                # 获取任务
                task_index, task = await task_queue.get()
                
                self.log(f"处理第 {task_index+1} 个任务: [{task.get('name', '')}]")
                
                # 获取历史数据
                success = await self.fetch_history_data(task, account_info)
                
                # 更新计数
                async with self.lock:
                    if success:
                        self.success_count += 1
                    else:
                        self.fail_count += 1
                        
                # 标记任务完成
                task_queue.task_done()
                
            except Exception as e:
                self.log(f"工作协程处理任务时发生错误: {str(e)}")
                traceback.print_exc()
    
    async def run_async(self):
        """异步运行历史数据抓取"""
        self.log("开始抓取任务历史数据...")
        
        # 获取有效任务
        tasks = self.get_active_tasks()
        if not tasks:
            self.log("没有有效任务，结束运行")
            return
            
        # 获取有效账号
        accounts = self.get_active_accounts(self.max_workers)
        if not accounts:
            self.log("没有有效账号，结束运行")
            return
            
        # 如果账号数量少于最大工作协程数，则调整工作协程数
        actual_workers = min(self.max_workers, len(accounts))
        self.log(f"将使用 {actual_workers} 个工作协程并行处理 {len(tasks)} 个任务")
        
        # 创建任务队列
        task_queue = asyncio.Queue()
        for i, task in enumerate(tasks):
            await task_queue.put((i, task))
            
        # 创建并启动工作协程
        workers = []
        for i in range(actual_workers):
            account_info = accounts[i % len(accounts)]
            worker = asyncio.create_task(self.worker(task_queue, account_info))
            workers.append(worker)
            
        # 等待所有任务完成
        await task_queue.join()
        
        # 取消所有工作协程
        for worker in workers:
            worker.cancel()
            
        # 等待所有工作协程取消完成
        await asyncio.gather(*workers, return_exceptions=True)
            
        self.log(f"任务历史数据抓取完成，成功: {self.success_count}，失败: {self.fail_count}")
    
    def run(self):
        """运行历史数据抓取"""
        # 创建事件循环并运行异步任务
        asyncio.run(self.run_async())

def main():
    """主函数"""
    fetcher = TaskHistoryDataFetcher(max_workers=5)  # 默认使用5个工作协程
    fetcher.run()
    
if __name__ == "__main__":
    main()
